---
title: "Android 开发基础"
description: "学习使用 Kotlin 进行 Android 开发，与 JavaScript 移动开发模式和 React Native 概念进行对比"
---

# Android 开发基础

欢迎来到 JavaScript 到 Kotlin 转换的第六个模块！在本模块中，我们将探索使用 Kotlin 进行 Android 开发，并了解它与 JavaScript 移动开发模式（如 React Native）的对比。我们将学习 Android 项目结构、Activity 生命周期、UI 组件和现代 Android 开发实践。

## 学习目标

通过本模块的学习，你将能够：
- 理解 Android 项目结构和架构
- 对比 Android 开发与 React Native 模式
- 实现 Activity 生命周期管理
- 有效创建和管理 Fragment
- 使用 XML 和 Compose 设计响应式布局
- 处理用户交互和事件
- 管理 Android 资源和资产
- 应用现代 Android 开发最佳实践

## Android 项目结构

### 项目组织

Android 项目具有特定的结构，与 JavaScript/React Native 项目有显著差异。让我们探索关键差异。

<UniversalEditor title="项目结构对比" compare={true}>
```javascript !! js
// React Native 项目结构
// App.js - 主应用程序组件
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

// HomeScreen.js - 屏幕组件
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const HomeScreen = ({ navigation }) => {
  const [count, setCount] = useState(0);
  
  return (
    <View style={styles.container}>
      <Text style={styles.title}>欢迎使用 React Native</Text>
      <Text style={styles.counter}>计数: {count}</Text>
      <Button 
        title="增加" 
        onPress={() => setCount(count + 1)} 
      />
      <Button 
        title="前往详情" 
        onPress={() => navigation.navigate('Details')} 
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  counter: {
    fontSize: 18,
    marginBottom: 20,
  },
});

export default HomeScreen;
```

```kotlin !! kt
// Android 项目结构
// MainActivity.kt - 主活动
package com.example.myapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                val navController = rememberNavController()
                
                NavHost(navController = navController, startDestination = "home") {
                    composable("home") { HomeScreen(navController) }
                    composable("details") { DetailsScreen() }
                }
            }
        }
    }
}

// HomeScreen.kt - 屏幕组件
@Composable
fun HomeScreen(navController: NavController) {
    var count by remember { mutableStateOf(0) }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "欢迎使用 Android Compose",
            style = MaterialTheme.typography.headlineMedium
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
            text = "计数: $count",
            style = MaterialTheme.typography.bodyLarge
        )
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { count++ }) {
            Text("增加")
        }
        Spacer(modifier = Modifier.height(8.dp))
        Button(onClick = { navController.navigate("details") }) {
            Text("前往详情")
        }
    }
}
```
</UniversalEditor>

### 目录结构对比

**React Native 项目结构：**
```
MyReactNativeApp/
├── App.js                 # 主应用组件
├── package.json           # 依赖管理
├── src/
│   ├── screens/          # 屏幕组件
│   ├── components/       # 可复用组件
│   ├── navigation/       # 导航配置
│   └── utils/           # 工具函数
└── assets/              # 静态资源
```

**Android 项目结构：**
```
MyAndroidApp/
├── app/
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/com/example/myapp/
│   │   │   │   ├── MainActivity.kt      # 主活动
│   │   │   │   ├── ui/                  # UI 组件
│   │   │   │   ├── data/                # 数据层
│   │   │   │   └── utils/               # 工具类
│   │   │   ├── res/                     # 资源文件
│   │   │   │   ├── layout/              # 布局文件
│   │   │   │   ├── values/              # 值资源
│   │   │   │   ├── drawable/            # 图像资源
│   │   │   │   └── mipmap/              # 应用图标
│   │   │   └── AndroidManifest.xml      # 应用清单
│   │   └── test/                        # 测试代码
│   ├── build.gradle.kts                 # 模块构建配置
│   └── proguard-rules.pro              # 代码混淆规则
├── build.gradle.kts                     # 项目构建配置
└── settings.gradle.kts                  # 项目设置
```

## Activity 生命周期

### 生命周期管理

Android Activity 有复杂的生命周期，需要正确管理状态。让我们对比 React Native 的组件生命周期。

<UniversalEditor title="生命周期对比" compare={true}>
```javascript !! js
// React Native 组件生命周期
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';

const MyComponent = () => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  // 组件挂载时执行
  useEffect(() => {
    console.log('组件已挂载');
    fetchData();
    
    // 组件卸载时清理
    return () => {
      console.log('组件即将卸载');
      // 清理定时器、取消网络请求等
    };
  }, []);

  // 数据变化时执行
  useEffect(() => {
    if (data) {
      console.log('数据已更新:', data);
    }
  }, [data]);

  const fetchData = async () => {
    try {
      setIsLoading(true);
      const response = await fetch('https://api.example.com/data');
      const result = await response.json();
      setData(result);
    } catch (error) {
      console.error('获取数据失败:', error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <View>
      <Text>{isLoading ? '加载中...' : '数据已加载'}</Text>
    </View>
  );
};

export default MyComponent;
```

```kotlin !! kt
// Android Activity 生命周期
class MainActivity : ComponentActivity() {
    private var data: String? = null
    private var isLoading = true

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("MainActivity", "onCreate: 活动已创建")
        
        // 恢复保存的状态
        savedInstanceState?.let { bundle ->
            data = bundle.getString("data")
            isLoading = bundle.getBoolean("isLoading", true)
        }
        
        setContent {
            MyAppTheme {
                MyScreen(data, isLoading)
            }
        }
        
        fetchData()
    }

    override fun onStart() {
        super.onStart()
        Log.d("MainActivity", "onStart: 活动已开始")
    }

    override fun onResume() {
        super.onResume()
        Log.d("MainActivity", "onResume: 活动已恢复")
    }

    override fun onPause() {
        super.onPause()
        Log.d("MainActivity", "onPause: 活动已暂停")
        // 保存重要数据
    }

    override fun onStop() {
        super.onStop()
        Log.d("MainActivity", "onStop: 活动已停止")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MainActivity", "onDestroy: 活动已销毁")
        // 清理资源
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        Log.d("MainActivity", "onSaveInstanceState: 保存状态")
        outState.putString("data", data)
        outState.putBoolean("isLoading", isLoading)
    }

    private fun fetchData() {
        lifecycleScope.launch {
            try {
                isLoading = true
                // 模拟网络请求
                delay(2000)
                data = "从服务器获取的数据"
                isLoading = false
            } catch (error: Exception) {
                Log.e("MainActivity", "获取数据失败", error)
                isLoading = false
            }
        }
    }
}

@Composable
fun MyScreen(data: String?, isLoading: Boolean) {
    Column {
        Text(text = if (isLoading) "加载中..." else "数据已加载")
        data?.let { 
            Text(text = "数据: $it") 
        }
    }
}
```
</UniversalEditor>

### 生命周期对比表

| React Native 生命周期 | Android Activity 生命周期 | 说明 |
|----------------------|-------------------------|------|
| `useEffect(() => {}, [])` | `onCreate()` | 组件/活动创建时执行 |
| `useEffect(() => {}, [deps])` | `onResume()` | 组件/活动变为活跃状态 |
| `useEffect(() => { return cleanup }, [])` | `onPause()` | 组件/活动暂停时执行 |
| 组件卸载 | `onDestroy()` | 组件/活动销毁时执行 |
| 状态保存 | `onSaveInstanceState()` | 保存状态以应对配置变化 |

## Fragment 使用

### Fragment 基础

Fragment 是 Android 中用于构建灵活 UI 的组件，类似于 React Native 中的可复用组件。

<UniversalEditor title="Fragment 使用示例" compare={true}>
```javascript !! js
// React Native 可复用组件
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

const UserProfile = ({ user, onEdit }) => {
  return (
    <View style={styles.container}>
      <Text style={styles.name}>{user.name}</Text>
      <Text style={styles.email}>{user.email}</Text>
      <TouchableOpacity style={styles.button} onPress={onEdit}>
        <Text style={styles.buttonText}>编辑资料</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    margin: 8,
  },
  name: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 4,
  },
  email: {
    fontSize: 14,
    color: '#666',
    marginBottom: 12,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 8,
    borderRadius: 4,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 14,
  },
});

export default UserProfile;
```

```kotlin !! kt
// Android Fragment
class UserProfileFragment : Fragment() {
    private var _binding: FragmentUserProfileBinding? = null
    private val binding get() = _binding!!
    
    private var user: User? = null
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentUserProfileBinding.inflate(inflater, container, false)
        return binding.root
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 恢复保存的状态
        savedInstanceState?.let { bundle ->
            user = bundle.getParcelable("user")
        }
        
        setupUI()
    }
    
    private fun setupUI() {
        user?.let { user ->
            binding.tvName.text = user.name
            binding.tvEmail.text = user.email
        }
        
        binding.btnEdit.setOnClickListener {
            onEditClick()
        }
    }
    
    private fun onEditClick() {
        // 通知父活动
        (activity as? MainActivity)?.onEditUser(user)
    }
    
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        user?.let { outState.putParcelable("user", it) }
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
    
    companion object {
        fun newInstance(user: User): UserProfileFragment {
            return UserProfileFragment().apply {
                this.user = user
            }
        }
    }
}

// Fragment 布局文件 (fragment_user_profile.xml)
/*
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp"
    android:background="@drawable/card_background"
    android:layout_margin="8dp">

    <TextView
        android:id="@+id/tvName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"
        android:layout_marginBottom="4dp" />

    <TextView
        android:id="@+id/tvEmail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="#666666"
        android:layout_marginBottom="12dp" />

    <Button
        android:id="@+id/btnEdit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="编辑资料"
        android:background="@drawable/button_background"
        android:textColor="@android:color/white" />

</LinearLayout>
*/
```
</UniversalEditor>

### Fragment 生命周期

Fragment 有自己的生命周期，需要与 Activity 生命周期协调：

```kotlin
// Fragment 生命周期管理
class MyFragment : Fragment() {
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Fragment 附加到 Activity
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Fragment 创建
    }
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 创建 Fragment 的视图
        return inflater.inflate(R.layout.fragment_my, container, false)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 视图创建完成，可以初始化 UI 组件
    }
    
    override fun onStart() {
        super.onStart()
        // Fragment 变为可见
    }
    
    override fun onResume() {
        super.onResume()
        // Fragment 变为活跃状态
    }
    
    override fun onPause() {
        super.onPause()
        // Fragment 暂停
    }
    
    override fun onStop() {
        super.onStop()
        // Fragment 停止
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        // 视图被销毁，清理视图相关资源
    }
    
    override fun onDestroy() {
        super.onDestroy()
        // Fragment 被销毁
    }
    
    override fun onDetach() {
        super.onDetach()
        // Fragment 从 Activity 分离
    }
}
```

## 布局和 UI 组件

### XML 布局 vs Compose

Android 提供了两种 UI 构建方式：传统的 XML 布局和现代的 Compose。

<UniversalEditor title="布局对比" compare={true}>
```javascript !! js
// React Native 布局
import React from 'react';
import { View, Text, StyleSheet, ScrollView } from 'react-native';

const ProductList = ({ products }) => {
  return (
    <ScrollView style={styles.container}>
      {products.map(product => (
        <View key={product.id} style={styles.productCard}>
          <Text style={styles.productName}>{product.name}</Text>
          <Text style={styles.productPrice}>¥{product.price}</Text>
          <Text style={styles.productDescription}>{product.description}</Text>
        </View>
      ))}
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
  productCard: {
    backgroundColor: 'white',
    padding: 16,
    marginBottom: 12,
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  productName: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  productPrice: {
    fontSize: 16,
    color: '#007AFF',
    fontWeight: 'bold',
    marginBottom: 4,
  },
  productDescription: {
    fontSize: 14,
    color: '#666',
  },
});

export default ProductList;
```

```kotlin !! kt
// Android Compose 布局
@Composable
fun ProductList(products: List<Product>) {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        items(products) { product ->
            ProductCard(product = product)
        }
    }
}

@Composable
fun ProductCard(product: Product) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 6.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Text(
                text = product.name,
                style = MaterialTheme.typography.titleLarge,
                modifier = Modifier.padding(bottom = 8.dp)
            )
            Text(
                text = "¥${product.price}",
                style = MaterialTheme.typography.bodyLarge,
                color = MaterialTheme.colorScheme.primary,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(bottom = 4.dp)
            )
            Text(
                text = product.description,
                style = MaterialTheme.typography.bodyMedium,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        }
    }
}

// 传统 XML 布局 (activity_main.xml)
/*
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp" />

<!-- item_product.xml -->
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    app:cardElevation="4dp"
    app:cardCornerRadius="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/tvProductName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"
            android:layout_marginBottom="8dp" />

        <TextView
            android:id="@+id/tvProductPrice"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textColor="@color/primary"
            android:textStyle="bold"
            android:layout_marginBottom="4dp" />

        <TextView
            android:id="@+id/tvProductDescription"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="@color/text_secondary" />

    </LinearLayout>

</androidx.cardview.widget.CardView>
*/
```
</UniversalEditor>

### 响应式布局

Android 提供了多种方式创建响应式布局：

```kotlin
// Compose 响应式布局
@Composable
fun ResponsiveLayout() {
    val configuration = LocalConfiguration.current
    val screenWidth = configuration.screenWidthDp
    
    if (screenWidth >= 600) {
        // 平板布局 - 两列
        Row(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier
                    .weight(1f)
                    .padding(16.dp)
            ) {
                Text("左侧内容")
            }
            Column(
                modifier = Modifier
                    .weight(1f)
                    .padding(16.dp)
            ) {
                Text("右侧内容")
            }
        }
    } else {
        // 手机布局 - 单列
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp)
        ) {
            Text("主要内容")
        }
    }
}

// XML 响应式布局
/*
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="左侧内容" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="右侧内容" />

    </LinearLayout>

</LinearLayout>
*/
```

## 事件处理

### 用户交互处理

Android 提供了多种方式处理用户交互，类似于 React Native 的事件处理。

<UniversalEditor title="事件处理对比" compare={true}>
```javascript !! js
// React Native 事件处理
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, TextInput, Alert } from 'react-native';

const UserForm = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleSubmit = async () => {
    if (!name.trim() || !email.trim()) {
      Alert.alert('错误', '请填写所有字段');
      return;
    }

    setIsSubmitting(true);
    try {
      // 模拟网络请求
      await new Promise(resolve => setTimeout(resolve, 1000));
      Alert.alert('成功', '表单提交成功！');
      setName('');
      setEmail('');
    } catch (error) {
      Alert.alert('错误', '提交失败，请重试');
    } finally {
      setIsSubmitting(false);
    }
  };

  const handleInputChange = (field, value) => {
    switch (field) {
      case 'name':
        setName(value);
        break;
      case 'email':
        setEmail(value);
        break;
    }
  };

  return (
    <View style={{ padding: 16 }}>
      <TextInput
        style={{
          borderWidth: 1,
          borderColor: '#ccc',
          padding: 12,
          marginBottom: 12,
          borderRadius: 4,
        }}
        placeholder="姓名"
        value={name}
        onChangeText={(text) => handleInputChange('name', text)}
      />
      
      <TextInput
        style={{
          borderWidth: 1,
          borderColor: '#ccc',
          padding: 12,
          marginBottom: 12,
          borderRadius: 4,
        }}
        placeholder="邮箱"
        value={email}
        onChangeText={(text) => handleInputChange('email', text)}
        keyboardType="email-address"
      />
      
      <TouchableOpacity
        style={{
          backgroundColor: isSubmitting ? '#ccc' : '#007AFF',
          padding: 12,
          borderRadius: 4,
          alignItems: 'center',
        }}
        onPress={handleSubmit}
        disabled={isSubmitting}
      >
        <Text style={{ color: 'white', fontWeight: 'bold' }}>
          {isSubmitting ? '提交中...' : '提交'}
        </Text>
      </TouchableOpacity>
    </View>
  );
};

export default UserForm;
```

```kotlin !! kt
// Android 事件处理
@Composable
fun UserForm() {
    var name by remember { mutableStateOf("") }
    var email by remember { mutableStateOf("") }
    var isSubmitting by remember { mutableStateOf(false) }
    
    val context = LocalContext.current
    val scope = rememberCoroutineScope()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("姓名") },
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 12.dp)
        )
        
        OutlinedTextField(
            value = email,
            onValueChange = { email = it },
            label = { Text("邮箱") },
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Email
            ),
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 12.dp)
        )
        
        Button(
            onClick = {
                scope.launch {
                    handleSubmit(name, email, context) { submitting ->
                        isSubmitting = submitting
                    }
                }
            },
            enabled = !isSubmitting,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text(if (isSubmitting) "提交中..." else "提交")
        }
    }
}

private suspend fun handleSubmit(
    name: String,
    email: String,
    context: Context,
    onSubmittingChange: (Boolean) -> Unit
) {
    if (name.trim().isEmpty() || email.trim().isEmpty()) {
        Toast.makeText(context, "请填写所有字段", Toast.LENGTH_SHORT).show()
        return
    }

    onSubmittingChange(true)
    try {
        // 模拟网络请求
        delay(1000)
        Toast.makeText(context, "表单提交成功！", Toast.LENGTH_SHORT).show()
        // 清空表单
    } catch (error: Exception) {
        Toast.makeText(context, "提交失败，请重试", Toast.LENGTH_SHORT).show()
    } finally {
        onSubmittingChange(false)
    }
}

// 传统 View 事件处理
class UserFormActivity : AppCompatActivity() {
    private lateinit var binding: ActivityUserFormBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityUserFormBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        setupEventHandlers()
    }
    
    private fun setupEventHandlers() {
        binding.btnSubmit.setOnClickListener {
            val name = binding.etName.text.toString()
            val email = binding.etEmail.text.toString()
            
            if (name.trim().isEmpty() || email.trim().isEmpty()) {
                Toast.makeText(this, "请填写所有字段", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            
            // 处理表单提交
            handleFormSubmission(name, email)
        }
        
        binding.etName.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                // 实时验证输入
                validateInput()
            }
        })
    }
    
    private fun handleFormSubmission(name: String, email: String) {
        // 显示加载状态
        binding.btnSubmit.isEnabled = false
        binding.progressBar.visibility = View.VISIBLE
        
        // 模拟网络请求
        lifecycleScope.launch {
            try {
                delay(1000) // 模拟网络延迟
                Toast.makeText(this@UserFormActivity, "表单提交成功！", Toast.LENGTH_SHORT).show()
                // 清空表单
                binding.etName.setText("")
                binding.etEmail.setText("")
            } catch (error: Exception) {
                Toast.makeText(this@UserFormActivity, "提交失败，请重试", Toast.LENGTH_SHORT).show()
            } finally {
                binding.btnSubmit.isEnabled = true
                binding.progressBar.visibility = View.GONE
            }
        }
    }
    
    private fun validateInput() {
        val name = binding.etName.text.toString()
        val email = binding.etEmail.text.toString()
        
        binding.btnSubmit.isEnabled = name.trim().isNotEmpty() && email.trim().isNotEmpty()
    }
}
```
</UniversalEditor>

## 资源管理

### 资源文件组织

Android 使用资源文件系统来管理字符串、颜色、尺寸等，类似于 React Native 的常量管理。

<UniversalEditor title="资源管理对比" compare={true}>
```javascript !! js
// React Native 常量管理
// constants/Colors.js
export const Colors = {
  primary: '#007AFF',
  secondary: '#5856D6',
  success: '#34C759',
  warning: '#FF9500',
  error: '#FF3B30',
  background: '#F2F2F7',
  text: '#000000',
  textSecondary: '#8E8E93',
};

// constants/Strings.js
export const Strings = {
  welcome: '欢迎使用',
  login: '登录',
  register: '注册',
  email: '邮箱',
  password: '密码',
  submit: '提交',
  cancel: '取消',
  error: {
    network: '网络错误',
    invalidEmail: '邮箱格式不正确',
    passwordTooShort: '密码长度不足',
  },
};

// constants/Sizes.js
export const Sizes = {
  padding: {
    small: 8,
    medium: 16,
    large: 24,
  },
  fontSize: {
    small: 12,
    medium: 16,
    large: 20,
    title: 24,
  },
  borderRadius: {
    small: 4,
    medium: 8,
    large: 12,
  },
};

// 使用示例
import { Colors, Strings, Sizes } from '../constants';

const MyComponent = () => {
  return (
    <View style={{
      backgroundColor: Colors.background,
      padding: Sizes.padding.medium,
    }}>
      <Text style={{
        color: Colors.text,
        fontSize: Sizes.fontSize.large,
      }}>
        {Strings.welcome}
      </Text>
    </View>
  );
};
```

```kotlin !! kt
// Android 资源管理
// res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="primary">#007AFF</color>
    <color name="secondary">#5856D6</color>
    <color name="success">#34C759</color>
    <color name="warning">#FF9500</color>
    <color name="error">#FF3B30</color>
    <color name="background">#F2F2F7</color>
    <color name="text_primary">#000000</color>
    <color name="text_secondary">#8E8E93</color>
</resources>

// res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">欢迎使用</string>
    <string name="login">登录</string>
    <string name="register">注册</string>
    <string name="email">邮箱</string>
    <string name="password">密码</string>
    <string name="submit">提交</string>
    <string name="cancel">取消</string>
    
    <string name="error_network">网络错误</string>
    <string name="error_invalid_email">邮箱格式不正确</string>
    <string name="error_password_too_short">密码长度不足</string>
</resources>

// res/values/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="padding_small">8dp</dimen>
    <dimen name="padding_medium">16dp</dimen>
    <dimen name="padding_large">24dp</dimen>
    
    <dimen name="text_size_small">12sp</dimen>
    <dimen name="text_size_medium">16sp</dimen>
    <dimen name="text_size_large">20sp</dimen>
    <dimen name="text_size_title">24sp</dimen>
    
    <dimen name="corner_radius_small">4dp</dimen>
    <dimen name="corner_radius_medium">8dp</dimen>
    <dimen name="corner_radius_large">12dp</dimen>
</resources>

// 使用示例
@Composable
fun MyComponent() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(MaterialTheme.colorScheme.background)
            .padding(
                horizontal = dimensionResource(R.dimen.padding_medium),
                vertical = dimensionResource(R.dimen.padding_medium)
            )
    ) {
        Text(
            text = stringResource(R.string.welcome),
            style = MaterialTheme.typography.headlineMedium,
            color = MaterialTheme.colorScheme.onBackground
        )
    }
}

// 传统 View 使用
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)
        
        // 使用资源
        findViewById<TextView>(R.id.tvWelcome).apply {
            text = getString(R.string.welcome)
            setTextColor(ContextCompat.getColor(this@MyActivity, R.color.text_primary))
            textSize = resources.getDimension(R.dimen.text_size_large)
        }
    }
}
```
</UniversalEditor>

### 多语言支持

Android 提供了完善的多语言支持机制：

```kotlin
// 多语言资源文件
// res/values/strings.xml (默认语言)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">Welcome</string>
    <string name="login">Login</string>
    <string name="register">Register</string>
</resources>

// res/values-zh/strings.xml (中文)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">欢迎</string>
    <string name="login">登录</string>
    <string name="register">注册</string>
</resources>

// res/values-zh-rCN/strings.xml (简体中文)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">欢迎</string>
    <string name="login">登录</string>
    <string name="register">注册</string>
</resources>

// res/values-zh-rTW/strings.xml (繁体中文)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">歡迎</string>
    <string name="login">登錄</string>
    <string name="register">註冊</string>
</resources>

// 动态语言切换
class LanguageManager {
    companion object {
        fun setLocale(context: Context, languageCode: String) {
            val locale = Locale(languageCode)
            Locale.setDefault(locale)
            
            val config = context.resources.configuration
            config.setLocale(locale)
            
            context.createConfigurationContext(config)
        }
    }
}

// 在 Activity 中使用
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 设置语言
        val language = getSharedPreferences("settings", MODE_PRIVATE)
            .getString("language", "zh-CN") ?: "zh-CN"
        LanguageManager.setLocale(this, language)
        
        setContentView(R.layout.activity_main)
    }
}
```

## 现代 Android 开发最佳实践

### Jetpack Compose 优势

Jetpack Compose 是 Android 的现代 UI 工具包，提供了声明式 UI 开发方式：

```kotlin
// Compose 最佳实践
@Composable
fun ModernAndroidApp() {
    var currentScreen by remember { mutableStateOf("home") }
    
    MaterialTheme {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = { Text("现代 Android 应用") },
                    actions = {
                        IconButton(onClick = { /* 设置 */ }) {
                            Icon(Icons.Default.Settings, "设置")
                        }
                    }
                )
            },
            bottomBar = {
                BottomNavigation {
                    BottomNavigationItem(
                        icon = { Icon(Icons.Default.Home, "首页") },
                        label = { Text("首页") },
                        selected = currentScreen == "home",
                        onClick = { currentScreen = "home" }
                    )
                    BottomNavigationItem(
                        icon = { Icon(Icons.Default.Person, "个人") },
                        label = { Text("个人") },
                        selected = currentScreen == "profile",
                        onClick = { currentScreen = "profile" }
                    )
                }
            }
        ) { paddingValues ->
            when (currentScreen) {
                "home" -> HomeScreen(Modifier.padding(paddingValues))
                "profile" -> ProfileScreen(Modifier.padding(paddingValues))
            }
        }
    }
}

@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier.fillMaxSize()) {
        item {
            Text(
                text = "欢迎使用现代 Android 开发",
                style = MaterialTheme.typography.headlineMedium,
                modifier = Modifier.padding(16.dp)
            )
        }
        
        items(10) { index ->
            Card(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 16.dp, vertical = 4.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
            ) {
                Text(
                    text = "项目 ${index + 1}",
                    modifier = Modifier.padding(16.dp)
                )
            }
        }
    }
}
```

## 总结

在本模块中，我们探索了使用 Kotlin 进行 Android 开发的基础知识，并将其与 JavaScript/React Native 模式进行了对比。以下是关键要点：

### 涵盖的核心概念：
1. **项目结构**：Android 的有组织目录结构 vs React Native 的简化方法
2. **生命周期管理**：Activity 和 Fragment 生命周期 vs React 组件生命周期
3. **UI 开发**：XML 布局和 Compose vs React Native 的 StyleSheet 方法
4. **事件处理**：Android 的全面触摸系统 vs React Native 的手势处理
5. **资源管理**：Android 的资源系统 vs React Native 的资产方法
6. **现代实践**：Jetpack Compose 的声明式 UI vs React Native 的基于组件的方法

### Android 开发优势：
- **类型安全**：Kotlin 的强类型系统防止运行时错误
- **性能**：原生 Android 性能 vs JavaScript 桥接开销
- **平台集成**：直接访问 Android API 和系统功能
- **工具支持**：Android Studio 提供优秀的 IDE 支持
- **生态系统**：丰富的 Android 特定库和框架

### 最佳实践：
1. **使用 Jetpack Compose** 进行现代 UI 开发
2. **实现适当的生命周期管理** 以防止内存泄漏
3. **遵循 Material Design 指南** 以获得一致的用户体验
4. **使用 ViewModel** 进行状态管理和配置更改
5. **实现适当的错误处理** 和用户反馈
6. **优化性能** 使用 RecyclerView 和高效布局

### 下一步：
在下一个模块中，我们将探索使用 Kotlin 进行 Web 开发，包括 Spring Boot 框架和后端服务，继续我们从 JavaScript 到 Kotlin 开发模式的旅程。